﻿#region Imports
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using CommonUtilities.Attributes;
using CommonUtilities.Enums;
using CommonUtilities.Extensions;
using CommonUtilities.Messages;
using CommonUtilities.Models;
using CommonUtilities.Util;
#endregion

namespace EntertainmentManager.Models
{
    /// <summary>
    /// Stores info on episodes
    /// </summary>
    [Serializable]
    public class EpisodeInfo : UIToggleNotifier //: SeasonInfo
    {
        #region Declarations
        /// <summary>
        /// Backing field for <code>SeasonPadLength</code>
        /// </summary>
        private int seasonPadLength = 2;

        /// <summary>
        /// Backing field for <code>EpisodePadLength</code>
        /// </summary>
        private int episodePadLength = 2;
        #endregion Declarations

        #region Properties
        /// <summary>
        /// Series title
        /// </summary>
        [DataImportMap("TV_series")]
        [Description("Series name")]
        [DisplayName("Series")]
        [Sortable]
        [SortIndex(1)]
        public string SeriesTitle { get; set; }

        /// <summary>
        /// Season index
        /// </summary>
        [DataImportMap("Season#")]
        [Description("Season index")]
        [DisplayName("S#")]
        [Filterable]
        [Sortable]
        [SortIndex(2)]
        public int SeasonIndex { get; set; }

        /// <summary>
        /// Episode index
        /// </summary>
        [DataImportMap("Episode#")]
        [Description("Episode index")]
        [DisplayName("E#")]
        [Filterable]
        [Sortable]
        [SortIndex(3)]
        public int EpisodeIndex { get; set; }

        /// <summary>
        /// Episode URL
        /// </summary>
        //[ColumnType(typeof(Hyperlink))] // RKD - new attrib
        [DataImportMap("IMDb_url/ID")]
        [Description("IMDb url")]
        [DisplayName("URL")]
        [Sortable]
        [SortIndex(5)]
        public string ImdbUrl { get; set; }

        /// <summary>
        /// Episode title
        /// </summary>
        [DataImportMap("Title")]
        [Description("Episode Title")]
        [DisplayName("Title")]
        [Sortable]
        [SortIndex(4)]
        public string EpisodeTitle { get; set; }

        /// <summary>
        /// Episode description
        /// </summary>
        [DataImportMap("Description")]
        [DisplayName("Description")]
        [SortIndex(500)]
        public string Description { get; set; }

        /// <summary>
        /// Original air date
        /// </summary>
        [DataImportMap("Air date")]
        [DisplayName("Org. air date")]
        [Sortable]
        [SortIndex(600)]
        public DateTime OriginalAirDate { get; set; }

        /// <summary>
        /// Pad length for season index
        /// </summary>
        [Browsable(false)]
        private int SeasonPadLength { get { return seasonPadLength; } }

        /// <summary>
        /// Pad length for episode index
        /// </summary>
        [Browsable(false)]
        private int EpisodePadLength { get { return episodePadLength; } }

        /// <summary>
        /// Relative path of episode
        /// </summary>
        [Description("Relative path")]
        [DisplayName(@"..\ Path")]
        [SortIndex(710)]
        public string RelPath { get; set; }

        /// <summary>
        /// Full path of episode
        /// <para>(set in MainViewModel)</para>
        /// </summary>
        [Description("Actual path on disk")]
        [DisplayName("Path")]
        [SortIndex(711)]
        public string ActualPath { get; set; }

        private string fullPath;
        /// <summary>
        /// Full path of episode
        /// <para>(set by SeriesInfo)</para>
        /// </summary>
        [Description("Full path (Logical)")]
        [DisplayName("Path")]
        [SortIndex(712)]
        public string FullPath
        {
            get { return fullPath; }
            set
            {
                fullPath = value;

                if (fullPath.ValidatePath(ePathValidation.File))
                {
                    FileByteSize = new FileInfo(fullPath).GetLength();
                    FileSize = new MemoryMgmt(eByteValueType.B, FileByteSize).PracticalSize.Coalesce("0B");

                    SeasonPath = fullPath.GetDirectoryNameFull();
                    SeasonFolder = SeasonPath.GetDirectoryNameOnly();
                    SeriesPath = SeasonPath.GetDirectoryUp();
                    SeriesFolder = SeriesPath.GetDirectoryNameOnly();
                }
            }
        }

        private string fileExtn;
        /// <summary>
        /// File extension of episode
        /// </summary>
        [Description("File extension")]
        [DisplayName("Extn.")]
        [Filterable]
        [Sortable]
        [SortIndex(7)]
        public string FileExtn
        {
            get { return fileExtn; }
            set { fileExtn = value.Coalesce().RemoveExtnChars().ToUpper(); }
        }

        #region Derived properties
        /// <summary>
        /// File name of episode
        /// </summary>
        [Description("File name")]
        [DisplayName("File Name")]
        [Sortable]
        [SortIndex(6)]
        public string FileName { get { return "s{0}e{1} - {2}".FormatTextFromParams(SeasonIndex.PadLeft(SeasonPadLength, '0'), EpisodeIndex.PadLeft(EpisodePadLength, '0'), EpisodeTitle.Replace(": ", " - ")); } }

        /// <summary>
        /// File name of episode with extn.
        /// </summary>
        [Browsable(false)]
        public string FileNameFull { get { return FileName + "." + (FileExtn.IsNullOrEmpty() ? "*" : FileExtn.RemoveExtnChars()).ToLower(); } }

        [Description("Size in bytes")]
        [DisplayName("Bytes")]
        [Sortable]
        [SortIndex(998)]
        public long FileByteSize { get; private set; }

        [Description("Size")]
        [DisplayName("Size")]
        [SortIndex(999)]
        public string FileSize { get; private set; }

        /// <summary>
        /// Specifies if file for the episode exists
        /// </summary>
        // [Browsable(false)] // -- RKD uncomment
        [DisplayName("Exists?")]
        [SortIndex(1000)]
        public bool FileExists { get { try { return File.Exists(FullPath); } catch (Exception) { return false; } } }

        [Browsable(false)]
        [DisplayName("Season folder")]
        public string SeasonFolder { get; private set; }

        [Browsable(false)]
        [DisplayName("Season path")]
        public string SeasonPath { get; private set; }

        [Browsable(false)]
        [DisplayName("Series path")]
        public string SeriesPath { get; private set; }

        [Browsable(false)]
        [DisplayName("Series fodler")]
        public string SeriesFolder { get; private set; }
        #endregion Derived properties
        #endregion Properties

        #region Constructors
        /// <summary>
        /// Initializes a new default instance of <code>EntertainmentManager.Models.EpisodeInfo</code>
        /// </summary>
        public EpisodeInfo()
            : base()
        {

        }

        /// <summary>
        /// Initializes a new instance of <code>EntertainmentManager.Models.EpisodeInfo</code>
        /// from flat format against mapper
        /// </summary>
        /// <param name="headers">List of headers in flat format</param>
        /// <param name="data">Episode info in flat format</param>
        /// <param name="map">Mapping of headers in source and property names in model</param>
        public EpisodeInfo(List<object> headers, List<object> data, Dictionary<string, string> map)
            : this()
        {
            throw new InvalidOperationException("For use while reading EXCEL");
            object error = null;

            try
            {
                headers.ForEach(hdr =>
                {
                    error = hdr;

                    // RKD : correct indexing in case of import name mismatch
                    PropertyInfo prop = this.GetType().GetProperty(map.GetKeyFromValue<string, string>((string)hdr, true).Coalesce());
                    if (!prop.IsNull()) prop.SetValue(this, ChangeDatatype(headers, data, map, prop.PropertyType, hdr), null);

                    error = null;
                });
            }
            catch (Exception)
            {
                MessageBoxUtil.Show(true, "Error for: " + Convert.ToString(error)); // RKD debug
                throw;
            }
        }
        #endregion Constructors

        #region Methods
        /// <summary>
        /// Updates padding length of season and episode index
        /// </summary>
        /// <param name="seasonPadLength">Padding length for season index</param>
        /// <param name="episodePadLength">Padding length for episode index</param>
        public void UpdatePadLength(int seasonPadLength = 2, int episodePadLength = 2)
        {
            this.seasonPadLength = seasonPadLength;
            this.episodePadLength = episodePadLength;
        }

        /// <summary>
        /// Changes the type of data while populating episode info
        /// </summary>
        /// <param name="headers">List of headers in flat format</param>
        /// <param name="data">Episode info in flat format</param>
        /// <param name="map">Mapping of headers in source and property names in model</param>
        /// <param name="typ">Type of the property to be populated</param>
        /// <param name="currentHeader">Data of the header being processed</param>
        /// <returns></returns>
        private object ChangeDatatype(List<object> headers, List<object> data, Dictionary<string, string> map, Type typ, object currentHeader)
        {
            throw new InvalidOperationException("For use while reading EXCEL");

            try
            {
                int i = headers.IndexOf(currentHeader);

                if (typ == typeof(Int32))
                    return Convert.ToInt32(data.ElementAt(i));
                else if (typ == typeof(String))
                    return Convert.ToString(data.ElementAt(i));
                else if (typ == typeof(DateTime))
                    return Convert.ToDateTime(data.ElementAt(i));
                else
                    return data.ElementAt(i);
            }
            catch (Exception) { if (typ == typeof(DateTime)) return DateTime.MinValue; }

            return null;
        }
        #endregion Methods
    }

    [Serializable]
    public class EpisodeInfoMirror
    {
        #region Properties
        public string SeriesTitle { get; set; }
        public int SeasonIndex { get; set; }
        public int EpisodeIndex { get; set; }
        public string ImdbUrl { get; set; }
        public string EpisodeTitle { get; set; }
        public string Description { get; set; }
        public DateTime OriginalAirDate { get; set; }
        public string RelPath { get; set; }
        public string FullPath { get; set; }
        public string FileExtn { get; set; }
        public string FileName { get; set; }
        public string FileNameFull { get; set; }
        public long FileByteSize { get; set; }
        public string FileSize { get; set; }
        public string SeasonFolder { get; set; }
        public string SeasonPath { get; set; }
        public string SeriesPath { get; set; }
        public string SeriesFolder { get; set; }
        #endregion Properties
    }
}
